package com.ng.desktop.expansionsa.view.reporte;

import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.TableColumn;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.view.JRViewer;

import org.apache.commons.lang.StringUtils;

import com.ng.desktop.expansionsa.model.Alquiler;
import com.ng.desktop.expansionsa.model.EstadoAlquiler;
import com.ng.desktop.expansionsa.model.TipoCliente;
import com.ng.desktop.expansionsa.persistence.AlquilerPersistence;
import com.ng.desktop.expansionsa.services.NGFactoryBean;
import com.ng.framework.persistence.NGSearchCriteria;
import com.ng.framework.persistence.NGSearchParameter;
import com.ng.framework.persistence.NGSearchParameter.Type;
import com.ng.framework.persistence.NGSearchParameter.UnaryOperation;
import com.ng.framework.view.desktop.NGDatePicker;
import com.ng.framework.view.desktop.NGGUIUtils;
import com.ng.framework.view.desktop.table.NGCustomTable;
import com.ng.framework.view.desktop.table.NGTableModel;

public class ReporteAlquileresFrame extends JInternalFrame implements ActionListener {

	private static final long serialVersionUID = -3520256152265660488L;

	private static final String[] COLUMNAS = new String[] { "Fecha", "Cliente", "Tipo de Cliente", "Monto", "Estado", "Alerta", "Observaciones" };
	private static final Integer[] ANCHO_COLUMNAS = new Integer[] { 100, 305, 110, 100, 150, 100, 467 };
	private static final DateFormat FORMATO_FECHA = new SimpleDateFormat("dd/MM/yyyy");
	private static final ImageIcon ICONO_CON_NOTIFICACION = NGGUIUtils.getImageIcon("icons/exclamation-red.png");
	private static final ImageIcon ICONO_SIN_NOTIFICACION = NGGUIUtils.getImageIcon("icons/tick.png");
	
	private NGDatePicker datePickerFechaDesde;
	private NGDatePicker datePickerFechaHasta;
	private JComboBox comboBoxTipoCliente;
	private JComboBox comboBoxEstado;
	private JComboBox comboBoxNotificacion;
	private JButton buttonBuscar;
	private NGCustomTable tableAlquileres;
	private JButton buttonImprimir;
	private JButton buttonVolver;
	
	private AlquilerPersistence alquilerPersistence;
	
	public ReporteAlquileresFrame() {
		super("Reporte de Alquileres");
		
		this.setFrameIcon(NGGUIUtils.getImageIcon("icons/report.png"));
		
		this.buildGui();
	}
	
	private void buildGui() {
		Container contentPane = this.getContentPane();
		contentPane.setLayout(new GridBagLayout());
		
		contentPane.add(this.createPanelFiltros(), new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		contentPane.add(this.getButtonBuscar(), new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE, new Insets(5, 0, 5, 5), 0, 0));
		
		contentPane.add(new JScrollPane(this.getTableAlquileres(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), new GridBagConstraints(0, 1, 2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 5, 5, 5), 0, 0));
		
		contentPane.add(this.getButtonImprimir(), new GridBagConstraints(0, 2, 2, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
		
		contentPane.add(this.getButtonVolver(), new GridBagConstraints(0, 3, 2, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
	}
	
	private JPanel createPanelFiltros() {
		JPanel panelFiltros = new JPanel(new GridBagLayout());
		
		panelFiltros.add(new JLabel("Fecha desde:"), new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0));
		panelFiltros.add(this.getDatePickerFechaDesde(), new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0));
		
		panelFiltros.add(new JLabel("Fecha hasta:"), new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0));
		panelFiltros.add(this.getDatePickerFechaHasta(), new GridBagConstraints(1, 1, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0));
		
		panelFiltros.add(new JLabel("Tipo de cliente:"), new GridBagConstraints(0, 2, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0));
		panelFiltros.add(this.getComboBoxTipoCliente(), new GridBagConstraints(1, 2, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0));
		
		panelFiltros.add(new JLabel("Estado:"), new GridBagConstraints(0, 3, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0));
		panelFiltros.add(this.getComboBoxEstado(), new GridBagConstraints(1, 3, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0));
		
		panelFiltros.add(new JLabel("Alerta:"), new GridBagConstraints(0, 4, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0));
		panelFiltros.add(this.getComboBoxNotificacion(), new GridBagConstraints(1, 4, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0));
		
		return panelFiltros;
	}
	
	private NGDatePicker getDatePickerFechaDesde() {
		if(datePickerFechaDesde == null) {
			datePickerFechaDesde = new NGDatePicker();
		}
		return datePickerFechaDesde;
	}
	
	private NGDatePicker getDatePickerFechaHasta() {
		if(datePickerFechaHasta == null) {
			datePickerFechaHasta = new NGDatePicker();
		}
		return datePickerFechaHasta;
	}

	private JComboBox getComboBoxTipoCliente() {
		if(comboBoxTipoCliente == null) {
			comboBoxTipoCliente = new JComboBox();
			
			comboBoxTipoCliente.addItem(null);
			for(TipoCliente tipoCliente : TipoCliente.values()) {
				comboBoxTipoCliente.addItem(tipoCliente);
			}
		}
		
		return comboBoxTipoCliente;
	}
	
	private JComboBox getComboBoxEstado() {
		if(comboBoxEstado == null) {
			comboBoxEstado = new JComboBox();
			
			comboBoxEstado.addItem(null);
			for(EstadoAlquiler estado : EstadoAlquiler.values()) {
				comboBoxEstado.addItem(estado);
			}
		}
		
		return comboBoxEstado;
	}
	
	private JButton getButtonImprimir() {
		if(buttonImprimir == null) {
			buttonImprimir = NGGUIUtils.createIconButton("icons/printer.png", this);
		}
		
		return buttonImprimir;
	}
	
	private JButton getButtonVolver() {
		if(buttonVolver == null) {
			buttonVolver = NGGUIUtils.createTextButton("Volver", this);
		}
		
		return buttonVolver;
	}
	
	private JComboBox getComboBoxNotificacion() {
		if(comboBoxNotificacion == null) {
			comboBoxNotificacion = new JComboBox();
			
			comboBoxNotificacion.addItem(null);
			for(Opcion opcion : Opcion.values()) {
				comboBoxNotificacion.addItem(opcion);
			}
		}
		
		return comboBoxNotificacion;
	}
	
	private JButton getButtonBuscar() {
		if(buttonBuscar == null) {
			buttonBuscar = NGGUIUtils.createTextButton("Buscar", this);
		}
		
		return buttonBuscar;
	}
	
	private NGCustomTable getTableAlquileres() {
		if(tableAlquileres == null) {
			tableAlquileres	= new NGCustomTable(COLUMNAS);
			
			tableAlquileres.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
			for(int i = 0; i < ANCHO_COLUMNAS.length; i++) {
				TableColumn column = tableAlquileres.getColumnModel().getColumn(i);
				column.setPreferredWidth(ANCHO_COLUMNAS[i]);
			}
		}
		
		return tableAlquileres;
	}
	
	private List<NGSearchParameter> getSearchParameters() {
		List<NGSearchParameter> searchParameters = new ArrayList<NGSearchParameter>();
		
		String fechaDesde = this.getDatePickerFechaDesde().getText();
		if(StringUtils.isNotBlank(fechaDesde)) {
			searchParameters.add(new NGSearchParameter(Alquiler.class, "fecha", fechaDesde, Type.DATE, UnaryOperation.GREATER_THAN));
		}
		
		String fechaHasta = this.getDatePickerFechaHasta().getText();
		if(StringUtils.isNotBlank(fechaHasta)) {
			searchParameters.add(new NGSearchParameter(Alquiler.class, "fecha", fechaHasta, Type.DATE, UnaryOperation.SMALLER_THAN));
		}
		
		TipoCliente tipoCliente = (TipoCliente)this.getComboBoxTipoCliente().getSelectedItem();
		if(tipoCliente != null) {
			searchParameters.add(new NGSearchParameter(Alquiler.class, "cliente", tipoCliente.name(), Type.STRING, UnaryOperation.EQUALS, true, "tipoCliente"));
		}
		
		EstadoAlquiler estadoAlquiler = (EstadoAlquiler)this.getComboBoxEstado().getSelectedItem();
		if(estadoAlquiler != null) {
			searchParameters.add(new NGSearchParameter(Alquiler.class, "estadoAlquiler", estadoAlquiler.name(), Type.STRING, UnaryOperation.EQUALS));
		}
		
		Opcion opcion = (Opcion)this.getComboBoxNotificacion().getSelectedItem();
		if(opcion == Opcion.SI) {
			searchParameters.add(new NGSearchParameter(Alquiler.class, "detalles", FORMATO_FECHA.format(new Date()), Type.DATE, UnaryOperation.SMALLER_THAN, true, "fechaDevolucion"));
		}
		
		return searchParameters;
	}
	
	public enum Opcion {
		
		SI("Si"), NO("No");
		
		private String descripcion;
		
		Opcion(String descripcion) {
			this.descripcion = descripcion;
		}
		
		@Override
		public String toString() {
			return descripcion;
		}
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == this.getButtonBuscar()) {
			this.buscar();			
		} else if (e.getSource() == this.getButtonImprimir()) {
			this.imprimir();
		} else if(e.getSource() == this.getButtonVolver()) {
			this.dispose();
		}
	}
	
	private List<Alquiler> alquileres = null;
	
	private void buscar() {
		((NGTableModel)this.getTableAlquileres().getModel()).setRowCount(0);
		
		NGSearchCriteria searchCriteria = new NGSearchCriteria();
		for(NGSearchParameter searchParameter : this.getSearchParameters()) {
			searchCriteria.addNGSearchParameter(searchParameter);				
		}
		
		alquileres = this.getAlquilerPersistence().getAll(searchCriteria);
		
		Opcion opcion = (Opcion)this.getComboBoxNotificacion().getSelectedItem();
		for(Alquiler alquiler : alquileres) {
			if(opcion != Opcion.NO || !alquiler.getAlerta()) {
				tableAlquileres.addRow(new Object[] { FORMATO_FECHA.format(alquiler.getFecha()), alquiler.getCliente(), alquiler.getCliente().getTipoCliente(), alquiler.getMonto(),  alquiler.getEstadoAlquiler(), alquiler.getAlerta() ? ICONO_CON_NOTIFICACION : ICONO_SIN_NOTIFICACION, alquiler.getObservaciones()});
				tableAlquileres.setCellAlignment(tableAlquileres.getRowCount() - 1, 0, SwingConstants.RIGHT);
			} 
		}
	}
	
	private void imprimir() {
		Map<String, Object> parameters = new HashMap<String, Object>();
		
		String fechaDesde = this.getDatePickerFechaDesde().getText(); 
		parameters.put("fechaDesde", StringUtils.isNotBlank(fechaDesde) ? fechaDesde : "-");
		String fechaHasta = this.getDatePickerFechaHasta().getText(); 
		parameters.put("fechaHasta", StringUtils.isNotBlank(fechaHasta) ? fechaHasta : "-");
		TipoCliente tipoCliente = (TipoCliente)this.getComboBoxTipoCliente().getSelectedItem();
		parameters.put("tipoCliente", tipoCliente != null ? tipoCliente.toString() : "Todos");
		EstadoAlquiler estadoAlquiler = (EstadoAlquiler)this.getComboBoxEstado().getSelectedItem();
		parameters.put("estado", estadoAlquiler != null ? estadoAlquiler.toString() : "Todos");
		Opcion opcion = (Opcion)this.getComboBoxNotificacion().getSelectedItem();
		parameters.put("alerta", opcion != null ? opcion.toString() : "Todos");
		
		try {
			JasperReport report = JasperCompileManager.compileReport(ClassLoader.getSystemClassLoader().getResourceAsStream("reports/reporte_alquileres.jrxml"));
			JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(alquileres);
			JasperPrint jasperPrint = JasperFillManager.fillReport(
					report, parameters, dataSource);
			
			JRViewer jrv = new JRViewer(jasperPrint); 
			JDialog viewer = new JDialog(NGGUIUtils.findWindow(this),"Vista previa");
			viewer.setModal(true);
			viewer.setSize(800,600); 
			viewer.setLocationRelativeTo(null); 
			viewer.getContentPane().add(jrv);
			viewer.setVisible(true);
		} catch (JRException e1) {
			e1.printStackTrace();
			JOptionPane.showMessageDialog(this, "Ha ocurrido un error al generar el reporte. Por favor, comuníquese con el desarrollador de la aplicacón.", "Error", JOptionPane.ERROR_MESSAGE);
		}				

	}
	
	private AlquilerPersistence getAlquilerPersistence() {
		if(alquilerPersistence == null) {
			alquilerPersistence = (AlquilerPersistence) NGFactoryBean.getInstance().getBean("alquilerPersistence");
		}
		
		return alquilerPersistence;
	}
}
